#include "Temperature_logger.h"

extern char Logging_Trigger;
extern Switch_State Switch_Log_Temp;
extern unsigned int Brightness_Light_Level;
extern Switch_State Brightness_Set_Val;
extern char First_Log_Flag;

volatile unsigned char Latest_Logs[10] = {255,255,255,255,255,255,255,255,255,255};
volatile char Latest_Logs_Pointer = 0;

// Constants
//Look-up table for these sizes ->  512k, 1M, 2M, 4M, 8M, 16M, 32M, 64M
unsigned char DF_pagebits[]  ={  9,  9,  9,  9,  9,  10,  10,  11};	    //index of internal page address bits
//Look-up table for these sizes ->  512k, 1M,  2M,  4M,  8M, 16M, 32M, 64M
//AMARTYA unsigned int  DF_pagesize[]  ={264,264, 264, 264, 264, 528, 528,1056};	//index of pagesizes


// Globals
unsigned char PageBits;
//AMARTYA unsigned int  PageSize;

volatile Data_Ptr Data_Pointer;
// Functions

/*****************************************************************************
*
*	Function name : DF_SPI_init
*
*	Returns :		None
*
*	Parameters :	None
*
*	Purpose :		Sets up the HW SPI in Master mode, Mode 3
*					Note -> Uses the SS line to control the DF CS-line.
*
******************************************************************************/
void DF_SPI_init (void)
{
	
	PORTB |= (1<<PORTB3) | (1<<PORTB2) | (1<<PORTB1) | (1<<PORTB0);
	DDRB |= (1<<PORTB2) | (1<<PORTB1) | (1<<PORTB0);		//Set MOSI, SCK AND SS as outputs
	SPSR = (1<<SPI2X);                                      //SPI double speed settings
	SPCR = (1<<SPE) | (1<<MSTR) | (1<<CPHA) | (1<<CPOL);	//Enable SPI in Master mode, mode 3, Fosc/2

}

/*****************************************************************************
*
*	Function name : DF_SPI_RW
*
*	Returns :		Byte read from SPI data register (any value)
*
*	Parameters :	Byte to be written to SPI data register (any value)
*
*	Purpose :		Read and writes one byte from/to SPI master
*
******************************************************************************/
unsigned char DF_SPI_RW (unsigned char output)
{
	unsigned char input;
	
	SPDR = output;							//put byte 'output' in SPI data register
	while(!(SPSR & 0x80));					//wait for transfer complete, poll SPIF-flag
	input = SPDR;							//read value in SPI data reg.
	
	return input;							//return the byte clocked in from SPI slave
}		


/*****************************************************************************
*
*	Function name : Read_DF_status
*
*	Returns :		One status byte. Consult Dataflash datasheet for further
*					decoding info
*
*	Parameters :	None
*
*	Purpose :		Status info concerning the Dataflash is busy or not.
*					Status info concerning compare between buffer and flash page
*					Status info concerning size of actual device
*
******************************************************************************/
unsigned char Read_DF_status (void)
{
	unsigned char result,index_copy;
	
	DF_CS_inactive;							//make sure to toggle CS signal in order
	DF_CS_active;							//to reset dataflash command decoder
	result = DF_SPI_RW(StatusReg);			//send status register read op-code
	result = DF_SPI_RW(0x00);				//dummy write to get result
	
	index_copy = ((result & 0x38) >> 3);	//get the size info from status register
	PageBits   = DF_pagebits[index_copy];	//get number of internal page address bits from look-up table
//AMARTYA	PageSize   = DF_pagesize[index_copy];   //get the size of the page (in bytes)
	return result;							//return the read status register value
}


/*****************************************************************************
*
*	Function name : Page_To_Buffer
*
*	Returns :		None
*
*	Parameters :	BufferNo	->	Decides usage of either buffer 1 or 2
*					PageAdr		->	Address of page to be transferred to buffer
*
*	Purpose :		Transfers a page from flash to dataflash SRAM buffer
*					
******************************************************************************/
void Page_To_Buffer (unsigned int PageAdr, unsigned char BufferNo)
{
	DF_CS_inactive;												//make sure to toggle CS signal in order
	DF_CS_active;												//to reset dataflash command decoder
	
	if (1 == BufferNo)											//transfer flash page to buffer 1
	{
		DF_SPI_RW(FlashToBuf1Transfer);							//transfer to buffer 1 op-code
		DF_SPI_RW((unsigned char)(PageAdr >> (16 - PageBits)));	//upper part of page address
		DF_SPI_RW((unsigned char)(PageAdr << (PageBits - 8)));	//lower part of page address
		DF_SPI_RW(0x00);										//don't cares
	}
#ifdef USE_BUFFER2
	else	
	if (2 == BufferNo)											//transfer flash page to buffer 2
	{
		DF_SPI_RW(FlashToBuf2Transfer);							//transfer to buffer 2 op-code
		DF_SPI_RW((unsigned char)(PageAdr >> (16 - PageBits)));	//upper part of page address
		DF_SPI_RW((unsigned char)(PageAdr << (PageBits - 8)));	//lower part of page address
		DF_SPI_RW(0x00);										//don't cares
	}
#endif
	
	DF_CS_inactive;												//initiate the transfer
	DF_CS_active;
	
	while(!(Read_DF_status() & 0x80));							//monitor the status register, wait until busy-flag is high
}


/*****************************************************************************
*
*	Function name : Buffer_Write_Enable
*
*	Returns :		None
*
*	Parameters :	IntPageAdr	->	Internal page address to start writing from
*					BufferAdr	->	Decides usage of either buffer 1 or 2
*					
*	Purpose :		Enables continous write functionality to one of the dataflash buffers
*					buffers. NOTE : User must ensure that CS goes high to terminate
*					this mode before accessing other dataflash functionalities 
*
******************************************************************************/
void Buffer_Write_Enable (unsigned char BufferNo, unsigned int IntPageAdr)
{
	DF_CS_inactive;								//make sure to toggle CS signal in order
	DF_CS_active;								//to reset dataflash command decoder
	
	if (1 == BufferNo)							//write enable to buffer 1
	{
		DF_SPI_RW(Buf1Write);					//buffer 1 write op-code
		DF_SPI_RW(0x00);						//don't cares
		DF_SPI_RW((unsigned char)(IntPageAdr>>8));//upper part of internal buffer address
		DF_SPI_RW((unsigned char)(IntPageAdr));	//lower part of internal buffer address
	}
	
//#ifdef USE_BUFFER2
	else
	if (2 == BufferNo)							//write enable to buffer 2
	{
		DF_SPI_RW(Buf2Write);					//buffer 2 write op-code
		DF_SPI_RW(0x00);						//don't cares
		DF_SPI_RW((unsigned char)(IntPageAdr>>8));//upper part of internal buffer address
		DF_SPI_RW((unsigned char)(IntPageAdr));	//lower part of internal buffer address
	}
//#endif
}




/*****************************************************************************
*
*	Function name : Buffer_To_Page
*
*	Returns :		None
*
*	Parameters :	BufferAdr	->	Decides usage of either buffer 1 or 2
*					PageAdr		->	Address of flash page to be programmed
*
*	Purpose :		Transfers a page from dataflash SRAM buffer to flash
*					
******************************************************************************/
void Buffer_To_Page (unsigned char BufferNo, unsigned int PageAdr)
{
	DF_CS_inactive;												//make sure to toggle CS signal in order
	DF_CS_active;												//to reset dataflash command decoder
		
	if (1 == BufferNo)											//program flash page from buffer 1
	{
		DF_SPI_RW(Buf1ToFlashWE);								//buffer 1 to flash with erase op-code
		DF_SPI_RW((unsigned char)(PageAdr >> (16 - PageBits)));	//upper part of page address
		DF_SPI_RW((unsigned char)(PageAdr << (PageBits - 8)));	//lower part of page address
		DF_SPI_RW(0x00);										//don't cares
	}

//#ifdef USE_BUFFER2
	else	
	if (2 == BufferNo)											//program flash page from buffer 2
	{
		DF_SPI_RW(Buf2ToFlashWE);								//buffer 2 to flash with erase op-code
		DF_SPI_RW((unsigned char)(PageAdr >> (16 - PageBits)));	//upper part of page address
		DF_SPI_RW((unsigned char)(PageAdr << (PageBits - 8)));	//lower part of page address
		DF_SPI_RW(0x00);										//don't cares
	}
//#endif
	
	DF_CS_inactive;												//initiate flash page programming
	DF_CS_active;												
	
	while(!(Read_DF_status() & 0x80));							//monitor the status register, wait until busy-flag is high
}


/*****************************************************************************
*
*	Function name : Cont_Flash_Read_Enable
*
*	Returns :		None
*
*	Parameters :	PageAdr		->	Address of flash page where cont.read starts from
*					IntPageAdr	->	Internal page address where cont.read starts from
*
*	Purpose :		Initiates a continuous read from a location in the DataFlash
*					
******************************************************************************/
void Cont_Flash_Read_Enable (unsigned int PageAdr, unsigned int IntPageAdr)
{
	DF_CS_inactive;																//make sure to toggle CS signal in order
	DF_CS_active;																//to reset dataflash command decoder
	
	DF_SPI_RW(ContArrayRead);													//Continuous Array Read op-code
	DF_SPI_RW((unsigned char)(PageAdr >> (16 - PageBits)));						//upper part of page address
	DF_SPI_RW((unsigned char)((PageAdr << (PageBits - 8))+ (IntPageAdr>>8)));	//lower part of page address and MSB of int.page adr.
	DF_SPI_RW((unsigned char)(IntPageAdr));										//LSB byte of internal page address
	DF_SPI_RW(0x00);															//perform 4 dummy writes
	DF_SPI_RW(0x00);															//in order to intiate DataFlash
	DF_SPI_RW(0x00);															//address pointers
	DF_SPI_RW(0x00);
}


char Flash_SPI_Check(void)
{
	char Mfd_Id = 0;
	
  	DF_CS_inactive;												//initiate the transfer
	DF_CS_active;
   
   DF_SPI_RW(0x9F);
   Mfd_Id = DF_SPI_RW(0x00);
   
   DF_CS_inactive;		
 
 	if (Mfd_Id!= 0x1F)
	{
    LCD_Clear();
	while (1)				// If the SPI communication fails, device must hang and display error code 1.
	{
	LCD_TEXT("FATAL");
	delay_ds(3);
	}
	}
	return (Mfd_Id);	//Correct MFID is 0x1F;
 
}


void Store_Log_Flash(void)
{
	int Light=0;
	unsigned int Light_Level;
	
	if (Logging_Trigger==1)
	{
		if(Switch_Log_Temp==On_Sw)
		{
			if (Brightness_Set_Val==On_Sw)
			{
				Light=getLight();
				Light_Level=1;
				while(Light<499)
				{
					Light_Level=(Light_Level*10)+1;
					Light+=100;
				};
				if (Light_Level>=Brightness_Light_Level)
				{
					//Only now should the data be logged!!!!
					Write_To_DFlash();
					//LCD_TEXT("LOGING");
					delay_ds(2);
				}
			}
			else 
			{	// Always log regardless of brighness value
				//Only now should the data be logged!!!!
					Write_To_DFlash();
					//LCD_TEXT("LOGING");
					delay_ds(2);	
			}
		}
			
	}
}

void Write_To_DFlash(void)
{
	unsigned int Actual_Addr;
	unsigned int Actual_Page;
	char Temperature;
	int i=0;
	T_Data Max_Temp,Min_Temp;
	
	
	// READ THE DATA POINTER FROM FLASH
	 Cont_Flash_Read_Enable(0,12); // LOC 12 ,13, 14, 15 contain Pointer
	 Data_Pointer.Page_Addr_Msb = DF_SPI_RW(0);
	 Data_Pointer.Page_Addr_Lsb = DF_SPI_RW(0);
	 Data_Pointer.Page_No_Msb = DF_SPI_RW(0);
	 Data_Pointer.Page_No_Lsb = DF_SPI_RW(0);
	 DF_CS_inactive;		
	 
	Actual_Addr = (Data_Pointer.Page_Addr_Msb<<8) + (Data_Pointer.Page_Addr_Lsb);
	Actual_Page = (Data_Pointer.Page_No_Msb<<8) + (Data_Pointer.Page_No_Lsb);
	// BASED ON POINTER, IF ADDRESS IS 264, LOAD BUFFER TO MAIN MEMORY, INCREMENT PAGE COUNT, RESET ADDRESS
	// ELSE LOAD TO BUFFER ALONE. INCREMENT ADDRESS
	
	Temperature=getTemperature();						// addition of array[10] for latest logs (ram)
	if(Latest_Logs_Pointer>9) 							//
	{													//
		Latest_Logs_Pointer = 0;						//
	}													//
	Latest_Logs[Latest_Logs_Pointer] = Temperature; 	//
	Latest_Logs_Pointer++;								//
	
	if(First_Log_Flag==0)
	{
		First_Log_Flag = 1; 
	}
	
	if (Actual_Addr<=258) //CHCK ATLEAST SPACE FOR 1 DATASET MORE.
	{	
		Buffer_Write_Enable(1,Actual_Addr);
		DF_SPI_RW(Temperature);
		//DF_SPI_RW(123);
		DF_SPI_RW(gHour);
		DF_SPI_RW(gMinute);
		DF_SPI_RW(gDay);
		DF_SPI_RW(gMonth);
		DF_SPI_RW(gYear);
		DF_CS_inactive;		
		
		Actual_Addr+=6;
	}
	else	// Load buffer to main mem
	{
		 Buffer_To_Page(1,Actual_Page);	//Buffer is loaded to Flash Main Array
		 DF_CS_inactive;		
		 
		 //Now, its better to load the buffer with "FF" in all locations to prepare for new inputs.
		 Buffer_Write_Enable(1,0);
		 for (i=0;i<264;i++)
		 {
			DF_SPI_RW(0xFF);
		 }
		 DF_CS_inactive;		
		 
		 if (Actual_Page == 2047)
		 Actual_Page = 0;
		 else 
		 Actual_Page+=1;
		 
		Actual_Addr=0;
		
		//Temperature=getTemperature();
		Buffer_Write_Enable(1,Actual_Addr);
		DF_SPI_RW(Temperature);
		//DF_SPI_RW(123);
		DF_SPI_RW(gHour);
		DF_SPI_RW(gMinute);
		DF_SPI_RW(gDay);
		DF_SPI_RW(gMonth);
		DF_SPI_RW(gYear);
		DF_CS_inactive;		
			
		Actual_Addr+=6;
		 
	 }

	// UPDATE POINTER IN FLASH BY FIRST TO BUFFER AND THEN TO MAIN MEMORY PAGE0. TAKE CARE TO LOAD THE PREV MAX AND MIN VALUES STORED ALSO IN PAGE0
	Cont_Flash_Read_Enable(0,0);
	Max_Temp.Temperature=DF_SPI_RW(0);
	Max_Temp.HH=DF_SPI_RW(0);
	Max_Temp.MI=DF_SPI_RW(0);
	Max_Temp.DD=DF_SPI_RW(0);
	Max_Temp.MM=DF_SPI_RW(0);
	Max_Temp.YY=DF_SPI_RW(0);

	Min_Temp.Temperature=DF_SPI_RW(0);
	Min_Temp.HH=DF_SPI_RW(0);
	Min_Temp.MI=DF_SPI_RW(0);
	Min_Temp.DD=DF_SPI_RW(0);
	Min_Temp.MM=DF_SPI_RW(0);
	Min_Temp.YY=DF_SPI_RW(0);
	
	DF_CS_inactive;	
	
	//Make modifications to MAX and MIN temperatures here
	if (Min_Temp.Temperature > Temperature)
	{
	Min_Temp.Temperature=Temperature;
	Min_Temp.HH=gHour;
	Min_Temp.MI=gMinute;
	Min_Temp.DD=gDay;
	Min_Temp.MM=gMonth;
	Min_Temp.YY=gYear;
	}
	if (Max_Temp.Temperature < Temperature)
	{
	Max_Temp.Temperature=Temperature;
	Max_Temp.HH=gHour;
	Max_Temp.MI=gMinute;
	Max_Temp.DD=gDay;
	Max_Temp.MM=gMonth;
	Max_Temp.YY=gYear;
	}

	Buffer_Write_Enable(2,0); //USE BUF2 FOR ALL POINTER UPDATIONS.
	DF_SPI_RW(Max_Temp.Temperature);
	DF_SPI_RW(Max_Temp.HH);
	DF_SPI_RW(Max_Temp.MI);
	DF_SPI_RW(Max_Temp.DD);
	DF_SPI_RW(Max_Temp.MM);
	DF_SPI_RW(Max_Temp.YY);
	DF_SPI_RW(Min_Temp.Temperature);
	DF_SPI_RW(Min_Temp.HH);
	DF_SPI_RW(Min_Temp.MI);
	DF_SPI_RW(Min_Temp.DD);
	DF_SPI_RW(Min_Temp.MM);
	DF_SPI_RW(Min_Temp.YY);	
	DF_SPI_RW((unsigned char)(Actual_Addr>>8));	
	DF_SPI_RW((unsigned char)(Actual_Addr));
	DF_SPI_RW((unsigned char)(Actual_Page>>8));
	DF_SPI_RW((unsigned char)(Actual_Page));
	//DF_SPI_RW(SPECIAL_SIGNATURE);
	DF_CS_inactive;	
	
	//Store from buffer to flash
	Buffer_To_Page(2,0);
	DF_CS_inactive;		
	
}

char Read_From_DFlash(signed int index)	//index=1 means Temperature1 @ Addr0,Page1, index=2 means Temperature2 @ Addr6,Page1 and so on....
{
	unsigned int Page_No;
	signed int Page_Addr;
	char Read_Data;
	//Index is 44*n,(44*n)+1,(44*n)+2,(44*n)+3  where n=0 to inf, Reserved Loc!

	Page_No = (index/44) + 1;
	Page_Addr = (index * 6) - (((index/44) * 264)+6);
	if ((Page_Addr<0) || (Page_Addr==0) || (Page_Addr==6) || (Page_Addr==12) )
	{return (255);
	}
	else 
	{
	Cont_Flash_Read_Enable(Page_No,Page_Addr);
	Read_Data = DF_SPI_RW(0);
	DF_CS_inactive;	
	}
}

void DF_Page0_init(void)
{
int i;
T_Data Max_Temp,Min_Temp;
Data_Ptr Present_Pointer;

//FLUSH BUFFER1....
Buffer_Write_Enable(1,0);
for (i=0;i<264;i++)
{
DF_SPI_RW(0xFF);
}
DF_CS_inactive;	

//FLUSH BUFFER2....
Buffer_Write_Enable(2,0);
for (i=0;i<264;i++)
{
DF_SPI_RW(0xFF);
}
DF_CS_inactive;	

Max_Temp.Temperature=0;
Max_Temp.HH=0;
Max_Temp.MI=0;
Max_Temp.DD=0;
Max_Temp.MM=0;
Max_Temp.YY=0;

Min_Temp.Temperature=60;
Min_Temp.HH=0;
Min_Temp.MI=0;
Min_Temp.DD=0;
Min_Temp.MM=0;
Min_Temp.YY=0;

Present_Pointer.Page_Addr_Msb=0;
Present_Pointer.Page_Addr_Lsb=0;
Present_Pointer.Page_No_Msb=0;	//ALL valid data stored from PAGE1!!!!!
Present_Pointer.Page_No_Lsb=1;

//STORE in Buffer
Buffer_Write_Enable(2,0);

DF_SPI_RW(Max_Temp.Temperature);
DF_SPI_RW(Max_Temp.HH);
DF_SPI_RW(Max_Temp.MI);
DF_SPI_RW(Max_Temp.DD);
DF_SPI_RW(Max_Temp.MM);
DF_SPI_RW(Max_Temp.YY);
DF_SPI_RW(Min_Temp.Temperature);
DF_SPI_RW(Min_Temp.HH);
DF_SPI_RW(Min_Temp.MI);
DF_SPI_RW(Min_Temp.DD);
DF_SPI_RW(Min_Temp.MM);
DF_SPI_RW(Min_Temp.YY);	
DF_SPI_RW(Present_Pointer.Page_Addr_Msb);	
DF_SPI_RW(Present_Pointer.Page_Addr_Lsb);
DF_SPI_RW(Present_Pointer.Page_No_Msb);
DF_SPI_RW(Present_Pointer.Page_No_Lsb);
   
 DF_CS_inactive;		
 
  //Store from buffer to flash
Buffer_To_Page(2,0);
delay_ds(1);
 
}

//BLOCK ERASE.. FULL FLASH!
//255 blocks (each block of 8 pages erased!)
void Erase_Dflash_Full(void)
{
	char Block_No=0;
	for(Block_No=0;Block_No<50;Block_No++)	//Do now for only 10 blocks..Later make it 255!!!
	{DF_CS_inactive;																//make sure to toggle CS signal in order
	DF_CS_active;																//to reset dataflash command decoder
	DF_SPI_RW(BlockErase);											//Block Erase op-code
	DF_SPI_RW((unsigned char)(Block_No >> 4));						//upper part of Block no
	DF_SPI_RW((unsigned char)(Block_No <<4));						//lower part of Block no
	DF_SPI_RW(0x00);									
	DF_CS_inactive;	
	delay_ds(1);
	}
}
// *****************************[ End Of DATAFLASH.C ]*************************

